/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2012/07/15
* File: DeviceWin32.cpp
* Blog: http://www.cnblogs.com/zengqh/
**/

#include "../Config/Config.h"

#ifdef RF_PLATFORM_WINDOWS

#include "CreateDeviceParams.h"
#include "../RenderSystem/OGLRenderSystem/OGLRenderSystem.h"
#include "../SceneManager/SceneManager.h"
#include "../RenderSystem/MaterialData.h"
#include "../RenderSystem/LightData.h"
#include "RenderWindow/RenderWin32.h"
#include "Input/InputSystem.h"
#include "DeviceWin32.h"

DeviceWin32::DeviceWin32(const CreateDeviceParams& param)
: _create_params(param)
, _render_system(NULL)
, _scene_manager(NULL)
{
	initDevice();
}

DeviceWin32::~DeviceWin32()
{

}

bool DeviceWin32::run()
{
	MSG msg;
	bool got_msg = false;
	bool quit = false;

	if (_render_window->isWindowActive())
	{
		got_msg = (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0);
	}
	else
	{
		got_msg = (::GetMessage(&msg, NULL, 0, 0) != 0);
	}

	if (got_msg)
	{
		::TranslateMessage(&msg);
		::DispatchMessage(&msg);
	}

	if (got_msg == WM_QUIT)
	{
		quit = true;
	}

	return !quit;
}

RenderSystem* DeviceWin32::getRenderSystem() const
{
	return _render_system;
}

SceneManager* DeviceWin32::getSceneManager() const
{
	return _scene_manager;
}

RenderWindow* DeviceWin32::getRenderWindow() const
{
	return _render_window;
}

InputSystem* DeviceWin32::getInputSystem() const
{
	return _input_system;
}

void DeviceWin32::onViewportUpdate(const Recti& view_port)
{
	if (_render_system)
	{
		_render_system->setViewport(view_port);
	}
}

void DeviceWin32::swap()
{
	RenderWin32* rw = static_cast<RenderWin32*>(_render_window);
	SwapBuffers(rw->getWindowDC());
}

bool DeviceWin32::initDevice()
{
	if (!createRenderWindow()) return false;
	if (!createInputSystem()) return false;
	if (!createRenderSystem()) return false;
	if (!createSceneManager()) return false;

	s32 window_width = _render_window->getWidth();
	s32 window_height = _render_window->getHeight();

	Recti view_port(0, 0, window_width, window_height);

	_render_system->setViewport(view_port);

	return true;
}

bool DeviceWin32::createRenderSystem()
{
	bool ret = false;
	switch(_create_params._device_type)
	{
	case DT_OPENGL:
		createOGLContext();
		_render_system = new OGLRenderSystem;
		ret = true;
		break;
	default:
		ret = false;
		break;
	}

	return ret;
}

bool DeviceWin32::createSceneManager()
{
	_scene_manager = new SceneManager(_render_system);
	return true;
}

bool DeviceWin32::createRenderWindow()
{
	_render_window = new RenderWin32;

	CreateWindowParams params;
	params._window_dimension = _create_params._window_dimension;

	bool ret = _render_window->createWindow(params);

	if (_render_window)	_render_window->addRenderTargetListener(this);

	return ret;
}

bool DeviceWin32::createOGLContext()
{
	GLuint		PixelFormat;

	RenderWin32* rw = static_cast<RenderWin32*>(_render_window);
	HDC _window_hdc = rw->getWindowDC();

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		16,											// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		16,											// 16Bit Z-Buffer (Depth Buffer)  
		0,											// No Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};


	if (!(PixelFormat=ChoosePixelFormat(_window_hdc, &pfd)))	
	{
		rf_assert(0);
		return false;								
	}

	if (!SetPixelFormat(_window_hdc,PixelFormat,&pfd))		
	{
		rf_assert(0);
		return false;									
	}

	if (!(_ogl_rc = wglCreateContext(_window_hdc)))				
	{
		rf_assert(0);
		return false;									
	}

	if (!wglMakeCurrent(_window_hdc, _ogl_rc))					
	{
		rf_assert(0);
		return false;									
	}

	return true;
}

bool DeviceWin32::createInputSystem()
{
	_input_system = InputSystem::createInputSystem();

	_input_system->initialise(_render_window);

	return true;
}

#endif